home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / OS⁄Toolbox / QuickDraw / RlePict / RlePict.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-08  |  11.1 KB  |  442 lines  |  [TEXT/KAHL]

  1. /*
  2.  * This software is copyrighted as noted below.  It may be freely copied,
  3.  * modified, and redistributed, provided that the copyright notice is 
  4.  * preserved on all copies.
  5.  * 
  6.  * There is no warranty or other guarantee of fitness for this software,
  7.  * it is provided solely "as is".  Bug reports or fixes may be sent
  8.  * to the author, who may or may not act on them as he desires.
  9.  *
  10.  * You may not include this software in a program or other software product
  11.  * without supplying the source, or without informing the end-user that the 
  12.  * source is available for no extra charge.
  13.  *
  14.  * If you modify this software, you should include a notice giving the
  15.  * name of the person performing the modification, the date of modification,
  16.  * and the reason for such modification.
  17.  */
  18. /*
  19.  * RLE File converter/translater
  20.  * John Peterson, Jan-Feb '91
  21.  *
  22.  * Copyright (c) 1991 John Peterson
  23.  *
  24.  * Stuff still to do:
  25.  * - Error recovery needs more work - sort out fatal errors (DONE)
  26.  * - Deal with memory allocation problems as a separate
  27.  *   error class, and have "emergancy stash" ready (DONE)
  28.  * - Should do something intelligent with basic color maps (DONE)
  29.  * - Be smarter about tying filenames to windows.
  30.  * - Check the machine/system configuration (DONE)
  31.  * - Windows should stack with offsets (so new ones don't
  32.  *   completly bury the old) (DONE)
  33.  * - Activate events should mess with the menus (DONE)
  34.  * - Finder stuff (File types, bundles, icons, etc). (DONE)
  35.  * _ Spencer's radius card.
  36.  * - Jamie Painter sez it croaks on empty PICT files from MacDraw (FIXED)
  37.  * Stuff maybe someday...
  38.  * - Be less of a memory hog (don't hold your breath, this
  39.  *     is lotsa work..)
  40.  * - Grow boxes/scroll bars (also lotsa work)
  41.  * - Zoom modes, other GetX11 frobs...
  42.  */
  43.  
  44. #include <StdLib.h>
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <QDOffscreen.h>
  48.  
  49. #include "rle.h"
  50. #include "macstuff.h"
  51. #include "macimg.h"
  52.  
  53. Ptr PanicStash;        /* Buffer to bring up an "out of memory" dialog */
  54.  
  55. rle_hdr inglob;        /* Globals for RLE lib */
  56.  
  57. /*
  58.  * Create a window for displaying an image.  RlePict's
  59.  * info is stashed in the WRefCon.
  60.  */
  61. static void
  62. CreateWindow( GWorldPtr gw, char * name )
  63. {
  64.     WindowPtr win;
  65.     ImageWin * imgWin;
  66.  
  67.     win = MakeWindow( gw->portRect.right - gw->portRect.left, 
  68.                       gw->portRect.bottom - gw->portRect.top, name );
  69.     CopyGWtoWindow( gw, win );
  70.  
  71.     imgWin = (ImageWin *) NewPtr( sizeof( ImageWin ));
  72.     if (!imgWin) MemoryError( "Can't create window - out of memory" );
  73.     imgWin->tag = 0xDEADBEEF;
  74.     imgWin->win = win;
  75.     imgWin->gw = gw;
  76.     imgWin->name = (char *) malloc( strlen( name ) + 1L );
  77.     if (! imgWin->name )
  78.         MemoryError( "Can't allocate window name" );
  79.     strcpy( imgWin->name, name );
  80.     SetWRefCon( win, (long) imgWin );
  81. }
  82.  
  83. /* 
  84.  * RLE to PICT file
  85.  */
  86. void
  87. RLEtoPICT()
  88. {
  89.     GWorldPtr mygw;
  90.     char namestore[256];
  91.     char * filename = namestore;
  92.     register rle_pixel *rptr, *gptr, *bptr, *aptr, *qdptr;
  93.     register long i, j;
  94.     PixMapPtr ppm;
  95.     long mapSize;
  96.     CTabPtr macCtab = NULL;
  97.     CTabHandle macCtabHandle = NULL;
  98.     rle_pixel **rows;
  99.     Rect r;
  100.     QDErr err;
  101.     WindowPtr win;
  102.     ImageWin * imgWin;
  103.     DialogPtr progressDlog;
  104.     char MMUMode = 1;        /* 1 = 32 bit mode */
  105.  
  106.     if ( !OldFilename( "RLE file:", filename, '????' ) )
  107.         return;
  108.     inglob.rle_file = fopen( filename, "rb" );
  109.     CHECK( inglob.rle_file, "Can't open RLE file\n" );
  110.     err = rle_get_setup( &inglob );
  111.     
  112.     /*
  113.      * Report error if it dies...
  114.      */
  115.     if (err != RLE_SUCCESS)
  116.     {
  117.         switch ( err )
  118.         {
  119.         case RLE_NOT_RLE:
  120.             ErrorAlert( "Tried to read a non-RLE file" );
  121.             break;
  122.             
  123.         case RLE_EMPTY:
  124.             ErrorAlert( "RLE file was empty" );
  125.             break;
  126.             
  127.         case RLE_EOF:
  128.             ErrorAlert( "RLE header was incomplete" );
  129.             break;
  130.             
  131.         default:
  132.             ErrorAlert( "Error encountered reading RLE file header" );
  133.             break;
  134.         }
  135.         fclose( inglob.rle_file );
  136.         return;
  137.     }
  138.     
  139.     if ( rle_row_alloc( &inglob, &rows ) )
  140.         MemoryError( "Ran out of memory\n" );
  141.         
  142.     r.left = inglob.xmin;
  143.     r.right = inglob.xmax + 1;
  144.     r.top = inglob.ymin;
  145.     r.bottom = inglob.ymax + 1;
  146.     
  147.     /*
  148.      * Do some sanity checks on the kind of file we're reading
  149.      * (We don't do funky channels or cmaps).
  150.      */
  151.     if (inglob.ncmap)
  152.         if ((inglob.cmaplen != 8) 
  153.             && (inglob.ncmap != 3)
  154.             && (inglob.ncmap != 1))
  155.         {
  156.             ErrorAlert( "Sorry - this image's color map not supported" );
  157.             fclose( inglob.rle_file );
  158.             return;
  159.         }
  160.         
  161.     if ((inglob.ncolors != 3) && (inglob.ncolors != 1))
  162.     {
  163.         ErrorAlert( "Sorry - only one and three channel RLE images" );
  164.         fclose( inglob.rle_file );
  165.         return;
  166.     }
  167.     
  168.     /* 
  169.      * If given a valid color map, convert it into a QuickDraw
  170.      * color map.
  171.      */
  172.     if (inglob.ncmap)
  173.     {        
  174.         mapSize = 1 << inglob.cmaplen;
  175.         
  176.         macCtabHandle = (CTabHandle) 
  177.                             NewHandle( sizeof( ColorTable ) + sizeof( ColorSpec ) * mapSize );
  178.         if ( !macCtabHandle )
  179.             MemoryError( "No memory for color map" );
  180.  
  181.         HLock( macCtabHandle );            /* I hate handles */
  182.         macCtab = *macCtabHandle;
  183.         macCtab->ctSeed = GetCTSeed();
  184.         macCtab->ctFlags = 0;            /* Not a device... */
  185.         macCtab->ctSize = mapSize - 1;
  186.         
  187.         for (i = 0; i < mapSize; i++)
  188.         {
  189.             macCtab->ctTable[i].value = i;
  190.             macCtab->ctTable[i].rgb.red = inglob.cmap[i];
  191.             macCtab->ctTable[i].rgb.green = (inglob.ncmap == 3) ? inglob.cmap[i+mapSize]
  192.                                                              : inglob.cmap[i];
  193.             macCtab->ctTable[i].rgb.blue = (inglob.ncmap == 3) ? inglob.cmap[i+2 * mapSize]
  194.                                                              : inglob.cmap[i];
  195.         }
  196.         HUnlock( macCtabHandle );
  197.     }
  198.     else
  199.     {
  200.         if (inglob.ncolors == 1)        /* One chan, no cmap, must be B&W */
  201.             macCtabHandle = GetCTable( 8 + 32 );    /* Built-in grayscale */
  202.         else
  203.             macCtabHandle = NULL;        /* No table */
  204.     }
  205.  
  206.     /* 
  207.      * Allocate an off-screen image ("GWorld" in MacSpeak) for
  208.      * storing the image.  Should check the error return.
  209.      */
  210.     err = NewGWorld( &mygw, (inglob.ncolors == 3) ? 32 : 8, &r, macCtabHandle, NULL, 0 );
  211.     if (err)
  212.         MemoryError( "Error converting RLE file, no memory for off-screen buffer" );
  213.     
  214.     /* CTable was copied into gworld, so get rid of our copy */
  215.     if (macCtabHandle)
  216.         DisposCTable( macCtabHandle );
  217.     
  218.     if (! LockPixels( mygw->portPixMap ))
  219.         MemoryError( "Can't lock memory for image" );
  220.  
  221.     progressDlog = InitProgress( 300 );        /* "Reading RLE" progress */
  222.     
  223.     HLock( mygw->portPixMap );
  224.     ppm = *(mygw->portPixMap);
  225.     
  226.     for (i = inglob.ymax; i >= inglob.ymin; i--)
  227.     {
  228.         rle_getrow( &inglob, rows );
  229.         if (inglob.ncolors == 3)
  230.         {
  231.             rptr = &(rows[0][inglob.xmin]);
  232.             gptr = &(rows[1][inglob.xmin]);
  233.             bptr = &(rows[2][inglob.xmin]);
  234.         }
  235.         else
  236.             rptr = gptr = bptr = &(rows[0][inglob.xmin]);
  237.         aptr = inglob.alpha ? rows[-1] : NULL;
  238.         
  239.         qdptr = (rle_pixel *) &(ppm->baseAddr[(long) (i - inglob.ymin) * (long) (ppm->rowBytes & 0x7FFF) + (long)0]);
  240.         /*
  241.          * Note qdptr may be pointing off to memory out on a 32 bit NuBus card.
  242.          * If so, then the MMU must be swapped into 32 bit mode to access the
  243.          * memory.  Leave it to Spencer to turn this up...
  244.          */
  245.         SwapMMUMode( &MMUMode );
  246.                 
  247.         if (inglob.ncolors == 1)
  248.         {
  249.             if (inglob.ncmap)
  250.                 for (j = inglob.xmin; j <= inglob.xmax; j++)
  251.                     *qdptr++ = *rptr++;
  252.             else
  253.                 for (j = inglob.xmin; j <= inglob.xmax; j++)    /* Convert to screwy Color QD */
  254.                     *qdptr++ = 255 - *rptr++;
  255.         }
  256.         else
  257.             /* 32 bit QuickDraw stores pixels in ARGBARGB... format */
  258.             for (j = inglob.xmin; j <= inglob.xmax; j++)
  259.             {
  260.                 *qdptr++ = aptr ? *aptr++ : 0xFF;
  261.                 *qdptr++ = *rptr++;
  262.                 *qdptr++ = *gptr++;
  263.                 *qdptr++ = *bptr++;
  264.             }
  265.  
  266.         SwapMMUMode( &MMUMode );
  267.  
  268.         if (i && (!(i % 10)))
  269.             UpdateProgress( progressDlog, 
  270.                             1.0 - ((double) (i - inglob.ymin))
  271.                             / (double) (inglob.ymax - inglob.ymin));
  272.     }
  273.     HUnlock( mygw->portPixMap );
  274.     fclose( inglob.rle_file );
  275.     UpdateProgress( progressDlog, 1.0 );
  276.     UnlockPixels( mygw->portPixMap );
  277.     CreateWindow( mygw, filename );
  278.     DoneProgress( progressDlog );
  279. }
  280.  
  281. /* 
  282.  * Save a GWorld as an RLE file.  The GWorld is assumed to be 32 bits
  283.  * deep.
  284.  */
  285. void
  286. PICTtoRLE(GWorldPtr mygw, char * defname)
  287. {
  288.     char namestore[256];
  289.     char * filename = namestore;
  290.     register rle_pixel *rptr, *gptr, *bptr, *aptr, *qdptr;
  291.     register long i, j;
  292.     PixMapPtr ppm;
  293.     rle_pixel **rows;
  294.     Rect r;
  295.     QDErr err;
  296.     DialogPtr progressDlog;
  297.     char MMUMode = 1;
  298.  
  299.     r = mygw->portRect;
  300.     
  301.     inglob = rle_dflt_hdr;        /* Initialize random stuff */
  302.     inglob.xmin = r.left;
  303.     inglob.xmax = r.right - 1;
  304.     inglob.ymin = r.top;
  305.     inglob.ymax = r.bottom - 1;
  306.     inglob.ncolors = 3;
  307.     inglob.alpha = 0;            /* QD32 stomped on it! */
  308.     
  309.     if (defname)
  310.         strcpy( filename, defname );
  311.     else
  312.         strcpy( filename, "RLE file" );
  313.     if (! NewFilename( "RLE filename:", filename ) )
  314.         return;
  315.         
  316.     CHECK( inglob.rle_file = fopen( filename, "wb" ), "Can't open output file" );
  317.     progressDlog = InitProgress( 200 );
  318.     rle_put_setup( &inglob );
  319.     if ( rle_row_alloc( &inglob, &rows ) )
  320.         MemoryError( "Can't allocate scanlines" );
  321.     
  322.     if ( !LockPixels( mygw->portPixMap ) )
  323.         MemoryError( "Can't lock pixels in memory" );
  324.  
  325.     HLock( mygw->portPixMap );
  326.  
  327.     ppm = *(mygw->portPixMap);
  328.  
  329.     for (i = inglob.ymax; i >= inglob.ymin; i--)
  330.     {
  331.         rptr = &(rows[0][0]);
  332.         gptr = &(rows[1][0]);
  333.         bptr = &(rows[2][0]);
  334.         
  335.         qdptr = (rle_pixel *) &(ppm->baseAddr[(long) (i - (long) inglob.ymin)
  336.                                     * (long) (ppm->rowBytes & 0x7FFF) + (long)0]);
  337.                                     
  338.         SwapMMUMode( &MMUMode );    /* …In case qdptr is off to a NuBus card */
  339.         
  340.         for (j = inglob.xmin; j <= inglob.xmax; j++)
  341.         {
  342.             qdptr++;
  343.             *rptr++ = *qdptr++;
  344.             *gptr++ = *qdptr++;
  345.             *bptr++ = *qdptr++;
  346.         }
  347.  
  348.         SwapMMUMode( &MMUMode );
  349.  
  350.         rle_putrow( rows, r.right - r.left, &inglob );
  351.         if (i && (!(i % 10)))
  352.             UpdateProgress( progressDlog, 
  353.                             1.0 - ((double) (i - inglob.ymin))
  354.                             / (double) (inglob.ymax - inglob.ymin));
  355.     }
  356.     HUnlock( mygw->portPixMap );
  357.  
  358.     UpdateProgress( progressDlog, 1.0 );
  359.     fclose( inglob.rle_file );
  360.     DoneProgress( progressDlog );
  361. }
  362.  
  363. /*
  364.  * The File menu drives the functionality of the
  365.  * program.
  366.  */
  367. void
  368. DoFileItem( short item )
  369. {
  370.     char namestore[256];
  371.     char * filename = namestore;
  372.     GWorldPtr gw;
  373.     ImageWin * imgWin;
  374.      GWorldFlags flags = (1L << (long)clipPixBit) | (1L << (long)ditherPixBit);   
  375.  
  376.     switch (item) 
  377.     {
  378.     case 1:            /* Open PICT */
  379.         if (!OldFilename( "PICT file:", filename, 'PICT' ))
  380.             return;
  381.         gw = LoadPicture( filename );
  382.         if (gw)
  383.             CreateWindow( gw, filename );
  384.         break;
  385.         
  386.     case 2:            /* Save PICT */
  387.         if (! (imgWin = (ImageWin *) GetWRefCon( FrontWindow() )))
  388.             return;
  389.             
  390.         if (imgWin->tag != 0xDEADBEEF)
  391.             return;
  392.             
  393.         if (imgWin->name)
  394.             strcpy( filename, imgWin->name );
  395.             
  396.         if (!NewFilename( "Save PICT file as:", filename ))
  397.             return;
  398.             
  399.         SavePicture( imgWin->gw, filename );
  400.         
  401.         break;
  402.         
  403.     case 4:            /* Load RLE */
  404.         RLEtoPICT();
  405.         break;
  406.         
  407.     case 5:            /* Save RLE */
  408.         if (! (imgWin = (ImageWin *) GetWRefCon( FrontWindow() )))
  409.             return;
  410.             
  411.         if (imgWin->tag != 0xDEADBEEF)
  412.             return;
  413.         /*
  414.          * Force image to be 32 bits per pixel.  Can only happen if we're
  415.          * writing an RLE file we read, which is a pretty silly thing
  416.          * to do anyway...
  417.          */
  418.         gw = imgWin->gw;
  419.         if ( (*(gw->portPixMap))->pixelSize != 32 )
  420.             flags = UpdateGWorld( &(imgWin->gw), 32, &gw->portRect, NULL, NULL, flags );
  421.             
  422.         if (flags & (1L << gwFlagErrBit))
  423.             MemoryError( "Can't expand pixmap to 32 bits" );
  424.     
  425.         PICTtoRLE( imgWin->gw, imgWin->name );
  426.         break;
  427.         
  428.     case 7:
  429.         ExitToShell();
  430.         break;
  431.     }
  432. }
  433.  
  434.  
  435. main()
  436. {
  437.     InitMac();
  438.     PanicStash = NewPtr( 5000L );    /* Hopefully enough to bring up an error & exit */
  439.     CreateMenus();
  440.     EventLoop();
  441. }
  442.